/**
 * 
 */
package com.williamoneil.charts.client.data;

import java.util.ArrayList;
import java.util.List;

/**
 * @author gudipati
 *
 */
public class PriceAxis {

	private double minPriceScale = 0;
	private double maxPriceScale = 0;
	
	private double majorIncrementsStepSize = -1;
	private double minorIncrementsStepSize = -1;
	
	private double minTickPrice = 0;
	private double maxTickPrice = 0;
	
	private boolean linear = true;

	public PriceAxis(final double minPrice, final double maxPrice, final boolean isLinear) {
		this.linear = isLinear;
		
		this.minTickPrice = minPrice;
		this.maxTickPrice = maxPrice;
		
		minPriceScale = minTickPrice * 0.8;
		maxPriceScale = maxTickPrice * 1.2;
		
		double priceDiff = maxPriceScale - minPriceScale;
		if(priceDiff == 0) {
			priceDiff = minPriceScale * 5;
		}
		
		double majorIncrements = 1;
//		double minorIncrements = 0.5;
		
		// for price diff > 100K, we use increments of 10K
		if(priceDiff >= 100000) {
			majorIncrements = 40000;
		} else if (priceDiff >= 50000) {
			majorIncrements = 25000;
		} else if (priceDiff >= 20000) {
			majorIncrements = 10000;
		} else if (priceDiff >= 10000) {
			majorIncrements = 2500;
		} else if (priceDiff >= 5000) {
			majorIncrements = 2000;
		} else if (priceDiff >= 2500) {
			majorIncrements = 1000;
		} else if (priceDiff >= 1000) {
			majorIncrements = 500;
		} else if (priceDiff >= 500) {
			majorIncrements = 200;
		} else if (priceDiff >= 200) {
			majorIncrements = 100;
		} else if (priceDiff >= 100) {
			majorIncrements = 50;
		} else if (priceDiff >= 50) {
			majorIncrements = 25;
		} else if (priceDiff >= 20) {
			majorIncrements = 10;
		} else if (priceDiff >= 10) {
			majorIncrements = 5;
		} else if (priceDiff >= 5) {
			majorIncrements = 2;
		} else if (priceDiff >= 2) {
			majorIncrements = 1;
		} else if (priceDiff >= 1) {
			majorIncrements = 0.5;
		} else if (priceDiff >= 0.5) {
			majorIncrements = 0.25;
		} else if (priceDiff >= 0.1) {
		 	majorIncrements = 0.05;
		} else {
			majorIncrements = 0.01;
		}
		
		majorIncrementsStepSize = majorIncrements;
		// lets keep 5 minor increment lines
		minorIncrementsStepSize = majorIncrementsStepSize / 5;
		
		if(priceDiff < 1) {
			//round the min and max price-scale to nearest integer
			
			minPriceScale = Math.floor(minPriceScale);
			maxPriceScale = Math.ceil(minPriceScale);
		}
		
		if(minPriceScale < 0) {
			minPriceScale = 0;
		}
	}
	
	public double getPrice(final int y, final ChartBoundsRect bounds) { 
		if(y < bounds.getY() || maxPriceScale <=0) {
			return -1;
		}
		
		if(linear) {
			return maxPriceScale - (((maxPriceScale - minPriceScale) * (y - bounds.getY())) / bounds.getHeightWithoutScale());
		} else {
			// log scale			
			return Math.pow(10, Math.log10(maxPriceScale) - (((Math.log10(maxPriceScale) - Math.log10(minPriceScale)) * (y - bounds.getY())) / bounds.getHeightWithoutScale()));
		}
	} 
	
	public int getY(final double price, final ChartBoundsRect bounds) {
		if(price <= 0 || maxPriceScale <= 0) {
			return -1;
		}
		
		if(linear) {
			return bounds.getY() + (int) Math.round(bounds.getHeightWithoutScale() * (maxPriceScale - price) / (maxPriceScale - minPriceScale));
		} else {
			// log
			return bounds.getY() + (int) Math.round(bounds.getHeightWithoutScale() * (Math.log10(maxPriceScale) - Math.log10(price)) / (Math.log10(maxPriceScale) - Math.log10(minPriceScale)));
		}
	}
	
	public List<HorizontalGridLine> getHorizontalGridLines(final ChartBoundsRect bounds) {
		if(maxPriceScale <= 0) {
			return null;
		}
		
		final List<HorizontalGridLine> hgLines = new ArrayList<HorizontalGridLine>();
		double gridLinePrice = minPriceScale ; 
		while(true) {
			gridLinePrice = gridLinePrice + minorIncrementsStepSize;
			if(gridLinePrice > maxPriceScale) {
				break;
			}
			
			final HorizontalGridLine hgl = new HorizontalGridLine();
			hgl.setValue(gridLinePrice);
			final int y = getY(gridLinePrice, bounds);
			if(y <= bounds.getY()) {
				break;
			}
			//hgl.setPosition(y);
			if((gridLinePrice - minPriceScale) % majorIncrementsStepSize == 0) {
				hgl.setMajor(true);
			} else {
				hgl.setMajor(false);
			}
			
			hgLines.add(hgl);
		}
		
		return hgLines;
	}
}
